﻿using System;
using System.Windows;
using StockAnalyst2.Chart;
using StockAnalyst2.Plugins.Visualization.Realtime;
using StockAnalyst2.StockGrid;
using StockAnalyst2.Plugins;
using StockAnalyst2.Plugins.Engine;
using StockAnalyst2.Plugins.Visualization.Historical;
using StockEngine.Historical;
using StockEngine.RealTime;
using Utils.Wpf;

namespace StockAnalyst2
{
	internal class MainWindowVM : ViewModelBase, IDisposable
	{
		#region Attributes

		private readonly Options.OptionsManager _appOptionsManager;
		private readonly StockGrid.OptionsManager _gridOptionsManager;
		private readonly ApplicationInitializer _applicationInitializer;
		private ApplicationCloser _applicationCloser;

		#endregion

		#region Properties

		public ApplicationCommandsVM ApplicationCommandsVM { get; private set; }
		public MainToolBarVM MainToolBarVM { get; private set; }
		public GridVM RealTimeGridVM { get; private set; }
		public GridVM HistoricalGridVM { get; private set; }
		public RealtimePluginViewerVM RealtimePluginViewerVM { get; private set; }
		public HistoricalPluginViewerVM HistoricalPluginViewerVM { get; private set; }
		public ChartCommandsVM ChartCommandsVM { get; private set; }
		public ChartViewerVM ChartViewerVM { get; private set; }
		public ChartToolBarVM ChartToolBarVM { get; private set; }
		public MainStatusBarVM MainStatusBarVM { get; private set; }
		public MainWindowStateVM MainWindowStateVM { get; private set; }
		public PluginSystemVM PluginSystemVM { get; private set; }

		#endregion

		#region Events

		public event EventHandler<DialogShowRequestedEventArgs> DialogShowRequested;
		public event EventHandler<MessageBoxRequestedEventArgs> MessageBoxRequested;
		public event EventHandler<PluginAttachRequestedEventArgs> PluginAttachRequested;

		#endregion

		#region Public Methods

		public MainWindowVM()
		{
			_appOptionsManager = new Options.OptionsManager();
			_appOptionsManager.DialogShowRequested += OptionsManager_DialogShowRequested; // Local object

			_applicationInitializer = new ApplicationInitializer();
			_gridOptionsManager = new StockGrid.OptionsManager();
		}

		public void Initialize()
		{
			// Options Manager must be the first object to initialize settings on first run ever
			_applicationInitializer.PluginSystem.PluginAttachRequested += PluginSystem_PluginAttachRequested; // Disposed

			_applicationInitializer.Initialize();
			_applicationInitializer.RealTimeSystem.Information.PropertyChanged += RealTimeSystem_Information_PropertyChanged; // Disposed
			_applicationInitializer.HistoricalSystem.PropertyChanged += HistoricalSystem_PropertyChanged; // Disposed

			_gridOptionsManager.DialogShowRequested += OptionsManager_DialogShowRequested; // Local object

			this.RealTimeGridVM = new GridVM(_applicationInitializer.RealTimeSystem.Groups, _gridOptionsManager.AllColumnsOptions);
			this.HistoricalGridVM = new GridVM(_applicationInitializer.HistoricalSystem.Groups, _gridOptionsManager.AllColumnsOptions);
			this.RealtimePluginViewerVM = new RealtimePluginViewerVM(_applicationInitializer.NotificationDataSource);
			this.HistoricalPluginViewerVM = new HistoricalPluginViewerVM();

			this.ChartViewerVM = new ChartViewerVM(_applicationInitializer.ChartGenerator.Data);
			this.ChartToolBarVM = new ChartToolBarVM();
			this.ChartCommandsVM = new ChartCommandsVM(_applicationInitializer.RawStockDataSource, _applicationInitializer.RealTimeSystem.Groups, _applicationInitializer.QuotationDataSource, this.ChartToolBarVM, this.ChartViewerVM, _applicationInitializer.ChartGenerator, this.ChartViewerVM.DataManager);

			this.ChartToolBarVM.ChartCommandsVM = this.ChartCommandsVM;

			_applicationCloser = new ApplicationCloser(_applicationInitializer.Accessor, _applicationInitializer.PluginSystem, _applicationInitializer.RealTimeSystem);

			this.MainToolBarVM = new MainToolBarVM(_applicationInitializer.RealTimeSystem, this.ChartToolBarVM);
			this.ApplicationCommandsVM = new ApplicationCommandsVM(_applicationInitializer.RealTimeSystem, _applicationCloser, _appOptionsManager, _gridOptionsManager, this.MainToolBarVM, _applicationInitializer.HistoricalSystem, _applicationInitializer.Accessor, this, this.ChartViewerVM);
			this.MainToolBarVM.ApplicationCommandsVM = this.ApplicationCommandsVM;
			
			this.MainStatusBarVM = new MainStatusBarVM(_applicationInitializer.Accessor, _applicationInitializer.RealTimeSystem, _applicationInitializer.HistoricalSystem);
			this.MainWindowStateVM = new MainWindowStateVM();
			this.PluginSystemVM = new PluginSystemVM(_applicationInitializer.PluginSystem);

			// Has to be initialized after the GridVM has been created
			_applicationInitializer.RealTimeSystem.InitializeSystem();
			_applicationInitializer.HistoricalSystem.InitializeSystem();

			_applicationInitializer.PluginSystem.LoadRealtimePlugins(this.RealtimePluginViewerVM);

			this.ApplicationCommandsVM.ErrorDetected += this.ApplicationCommandsVM_ErrorDetected; // Local object
			this.ChartCommandsVM.ErrorDetected += this.ChartCommandsVM_ErrorDetected; // Local object
			this.ChartCommandsVM.DialogShowRequested += this.ChartCommandsVM_DialogShowRequested;

			this.RealTimeGridVM.IsVisible = true;
		}

		protected virtual void OnDialogShowRequested(DialogShowRequestedEventArgs e)
		{
			if (this.DialogShowRequested != null)
			{
				this.DialogShowRequested(this, e);
			}
		}

		protected virtual void OnPluginAttachRequested(PluginAttachRequestedEventArgs e)
		{
			if (this.PluginAttachRequested != null)
			{
				this.PluginAttachRequested(this, e);
			}
		}

		protected virtual void OnMessageBoxRequested(string caption, string message, MessageBoxImage icon)
		{
			if (this.MessageBoxRequested != null)
			{
				this.MessageBoxRequested(this, new MessageBoxRequestedEventArgs(caption, message, icon));
			}
		}

		#endregion

		#region Event Handlers

		private void ChartCommandsVM_ErrorDetected(object sender, ErrorDectectedEventArgs e)
		{
			this.OnMessageBoxRequested("Error Detected", e.Message, MessageBoxImage.Error);
		}

		private void ApplicationCommandsVM_ErrorDetected(object sender, ErrorDectectedEventArgs e)
		{
			this.OnMessageBoxRequested("Error Detected", e.Message, MessageBoxImage.Error);
		}

		private void HistoricalSystem_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
		{
			if (e.PropertyName == "State")
			{
				this.HistoricalGridVM.IsPlaceHolderVisible = _applicationInitializer.HistoricalSystem.State != HistoricalSystemState.Loaded;
			}
		}

		private void OptionsManager_DialogShowRequested(object sender, DialogShowRequestedEventArgs e)
		{
			this.OnDialogShowRequested(e);
		}

		private void ChartCommandsVM_DialogShowRequested(object sender, DialogShowRequestedEventArgs e)
		{
			this.OnDialogShowRequested(e);
		}

		private void RealTimeSystem_Information_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
		{
			if (e.PropertyName == "State")
			{
				if (_applicationInitializer.RealTimeSystem.Information.State == AcquisitionSystemState.Enabling)
				{
					this.RealTimeGridVM.IsPlaceHolderVisible = true;
				}
				else if (_applicationInitializer.RealTimeSystem.Information.State == AcquisitionSystemState.Enabled)
				{
					this.RealTimeGridVM.IsPlaceHolderVisible = false;
				}
			}
		}

		private void PluginSystem_PluginAttachRequested(object sender, PluginAttachRequestedEventArgs e)
		{
			this.OnPluginAttachRequested(e);
		}

		#endregion

		#region IDisposable

		protected bool Disposed { get; private set; }

		private void Dispose(bool disposing)
		{
			if (!this.Disposed)
			{
				this.InternalDispose(disposing);
			}

			this.Disposed = true;
		}

		protected virtual void InternalDispose(bool disposing)
		{
			if (disposing)
			{
				this.MainStatusBarVM.Dispose();
				this.RealTimeGridVM.Stop();
				this.HistoricalGridVM.Stop();
				this.HistoricalPluginViewerVM.Dispose();
				this.RealtimePluginViewerVM.Dispose();
				this.PluginSystemVM.Dispose();
				this.MainToolBarVM.Dispose();
				this.RealTimeGridVM.Dispose();
				this.HistoricalGridVM.Dispose();
				
				_applicationInitializer.PluginSystem.PluginAttachRequested -= PluginSystem_PluginAttachRequested;
				_applicationInitializer.RealTimeSystem.Information.PropertyChanged -= RealTimeSystem_Information_PropertyChanged;
				_applicationInitializer.HistoricalSystem.PropertyChanged -= HistoricalSystem_PropertyChanged;

				_applicationInitializer.Dispose();
			}

			// Dispose here only unmanaged objects 
			// Don’t use managed objects here because maybe 
			// they have been finalized already
		}

		public void Dispose()
		{
			this.Dispose(true);
			GC.SuppressFinalize(this);
		}

		~MainWindowVM()
		{
			this.Dispose(false);
		}

		#endregion
	}
}
